package com.mairuide._frame.utils.excellistener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.mairuide._frame.utils.*;
import com.mairuide.bill.DealFlow;
import com.mairuide.bill.DealFlowService;
import com.mairuide.bill.utils.DateUtils;
import com.mairuide.excel_rule.pojo.ExcelRule;
import com.mairuide.exceltitle_dict.enum2.FieldTypeEnum;
import com.mairuide.exceltitle_dict.pojo.ExceltitleDict;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * Created by 敲代码的卡卡罗特
 * on 2019/3/21 11:08.
 * 通用的解析方法
 */
public class CommonDealFlowExcelListenerMapping extends AnalysisEventListener {
    private  List<DealFlow> list = new ArrayList<DealFlow>();
    private  List<DealFlow> data = new ArrayList<DealFlow>();
    private Map<Integer, ExceltitleDict> exceltitleDictMap = new HashMap<>();//存放标题头的对应关系
    private Map<Integer, ExceltitleDict> exceltitleDictMapBak = new HashMap<>();//存放标题头的对应关系备份，因为双标题头的时候要进行切换
    private Map<Integer, ExceltitleDict> exceltitleDictMap2 = new HashMap<>();//双标题头的 存放标题头的对应关系
    private Map<String, Object> multiTitleHeadDetail = null ;//存放标题头的对应关系  双标题头才有用
    DealFlow dealFlow2 = null; //双标题头才有用,存放上一个的信息
    private Map<String,Object> paraMap = new HashMap<String,Object>();  //参数MAP
    private Map<String,Object> resultMap = new HashMap<String,Object>();  //结果MAP
    private Map<String,String> title_attach_info_map=new HashMap<String,String>();//存放公共信息的map
    private Map<String,String> title_info_map=new HashMap<String,String>();//存放可循环的标题头信息的map
    private ExcelRule excelRule;
    DealFlow dealFlow = null;
    List<Map<String,Object>> title_info_detail_list=null;
    List<Map<String,Object>> title_attach_info_detail_list=null;
    private Integer multiTitleHeadFlag=0;//多标题头的标志，默认0，如果变成1的话就说明下一行的数据应该对应第二个标题头
    @Override
    public void invoke(Object object, AnalysisContext context) {
        try {
            List<String> s = (List<String>)object;
            s = s.stream().map(m -> {
                if (m!=null){
                    return m.replaceAll("\n|\n", "").trim();
                }else{
                    return null;
                }
            }).collect(Collectors.toList());
            Integer rowNum = context.getCurrentRowNum();//当前处于第几行
            //System.out.println("当前行："+rowNum+":::::::"+s);
            //遇到空白行跳过
            String join = StringUtils.join(s, "").trim();
            if (StringUtils.isBlank(join)) return;
            //遇到标题头就跳过
            String join2 = StringUtils.join(s, ",").trim();

            if (excelRule!=null&&StringUtils.equals(excelRule.getTitleHead(),join2)) {
                multiTitleHeadFlag=0;
                exceltitleDictMap=exceltitleDictMapBak;
                return;
            }
            if(excelRule!=null&&excelRule.getIsMultiTitleHead()!=null&&excelRule.getIsMultiTitleHead()==1){//双标题头的情况
                String multiTitleHeadDetailTemp = excelRule.getMultiTitleHeadDetail();
                if (multiTitleHeadDetail==null){
                    multiTitleHeadDetail = JsonUtil.string2Obj(multiTitleHeadDetailTemp, Map.class);
                }
                String col = multiTitleHeadDetail.get("col").toString();
                //得到第二个标题头的Map<Integer, ExceltitleDict>
                if (exceltitleDictMap2.size()==0){
                    List<Map<String, Object>> exceltitleDictMap2Temp = (List<Map<String, Object>>)multiTitleHeadDetail.get("map");
                    for (int i = 0; i <exceltitleDictMap2Temp.size() ; i++) {
                        Map<String, Object> value = exceltitleDictMap2Temp.get(i);
                        try {
                            ExceltitleDict exceltitleDict = BeanMapUtils.mapToBean(value, ExceltitleDict.class);
                            exceltitleDictMap2.put(Integer.valueOf(value.get("col").toString()),exceltitleDict);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
                if (StringUtils.equals(col,join2)) {
                    exceltitleDictMap=exceltitleDictMap2;
                    multiTitleHeadFlag=1;
                    return;
                }
            }
            //如果标题头的对应关系不存在就跳过
            if (exceltitleDictMap.size()==0) return;
            //碰到结束标志就跳过
            if (excelRule!=null&&excelRule.getIsEnd()==1){
                String endInfo = excelRule.getEndInfo();
                List<String> endInfoList = JsonUtil.string2Obj(endInfo, List.class);
                for (int i = 0; i < endInfoList.size(); i++) {
                    if (Pattern.matches(endInfoList.get(i), join)||join.contains(endInfoList.get(i))){
                        return;
                    }
                }
            }
            DealFlow dealFlow = new DealFlow();
            if (excelRule.getIsMultiTitleHead()!=null&&excelRule.getIsMultiTitleHead()==1){
                if (multiTitleHeadFlag==1) {
                    dealFlow=this.dealFlow2;
                }
            }
            Integer is_complex; //是否是复杂模板
            Integer title_head_line=0;//标题头在第几行
            Integer is_loop=0;//是否循环
            Integer is_title_attach_info=0;//有没有附加的信息
            String title_attach_info_detail="";//附加信息的详细值
            Integer is_title_info=0; //是否有标题头的信息，一般是循环可变的，紧挨在标题头的上面
            Integer is_loop_title_info=0; //标题头的详细信息是否循环
            String title_info_detail=""; //标题头的详细信息


            is_complex = excelRule.getIsComplex();
            title_head_line=excelRule.getTitleHeadLine();
            //如果是复杂模板
            if (is_complex==1) {
                //先判断有没有附加的信息
                is_title_attach_info = excelRule.getIsTitleAttachInfo();
                if (is_title_attach_info==1){ //有公共的附加的信息
                    title_attach_info_detail = excelRule.getTitleAttachInfoDetail();
                    title_attach_info_detail_list = JsonUtil.string2Obj(title_attach_info_detail, List.class);
                    for (int i = 0; i < title_attach_info_detail_list.size(); i++) {
                        Map<String, Object> map = title_attach_info_detail_list.get(i);
                        //第几行
                        Integer row = Integer.valueOf(map.get("row").toString());
                        if (row==rowNum){//得到当前行对应的值
                            List<Map<String,Object>> colList =(List<Map<String,Object>>) map.get("colList");
                            if (colList!=null){//如果不为空
                                for (Map<String, Object> m : colList){
                                    //第几列
                                    Integer col = Integer.valueOf(m.get("col").toString());
                                    //正则
                                    String  reg = m.get("reg").toString();
                                    //对应的值得字段
                                    List<Map<String,String>>  obj = (List) m.get("obj");
                                    //得到当前列的数据
                                    String s1 = s.get(col);
                                    List<String> group = RegUtil.getMatcher(reg, s1);
                                    for (int j = 0; j < obj.size(); j++) {
                                        Map<String, String> colmap = obj.get(j);
                                        //字段名称
                                        String fieldName = colmap.get("fieldName");
                                        //字段值位置
                                        Integer index = Integer.valueOf(colmap.get("index"));
                                        //字段的数据类型
                                        Integer fieldType = Integer.valueOf(colmap.get("fieldType"));
                                        //保存到map中先。格式  字段名字   字段值,字段类型
                                        title_attach_info_map.put(fieldName,group.get(index).trim()+","+fieldType);
                                    }
                                }
                            }
                        }
                    }
                }
                //再判断有没有循环的标题头的信息
                is_title_info=excelRule.getIsTitleInfo();
                 if (is_title_info==1){
                    is_loop_title_info=excelRule.getIsLoopTitleInfo();
                    if (is_loop_title_info==1){//说明是可循环的头信息
                        title_info_detail=excelRule.getTitleInfoDetail();
                        title_info_detail_list = JsonUtil.string2Obj(title_info_detail, List.class);
                        for (int i = 0; i < title_info_detail_list.size(); i++) {
                            Map<String,Object> o = title_info_detail_list.get(i);
                            //第几列
                            Integer col = Integer.valueOf(o.get("col").toString()) ;
                            //正则
                            String  reg =  o.get("reg").toString();
                            //对应的值得字段
                            List<Map<String,String>>  obj = (List) o.get("obj");
                            //循环标题头的格式必须符合条件
                            if (Pattern.matches(reg, join)){
                                //得到当前列的数据
                                String s1 = s.get(col);
                                List<String> group = RegUtil.getMatcher(reg, s1);
                                for (int j = 0; j < group.size(); j++) {
                                    if (j>=obj.size()) continue;
                                    Map<String, String> map = obj.get(j);
                                    //字段名称
                                    String fieldName = map.get("fieldName");
                                    //字段值位置
                                    Integer index = Integer.valueOf(map.get("index"));
                                    //字段的数据类型
                                    Integer fieldType = Integer.valueOf(map.get("fieldType"));
                                    //保存到map中先。格式  字段名字   字段值,字段类型
                                    title_info_map.put(fieldName,group.get(index).trim()+","+fieldType);
                                }
                            }
                        }
                    }
                }
            }
            //当前行小于标题头所在行跳过
            if (rowNum<=excelRule.getTitleHeadLine()) return;
            //当这一行是循环标题体头信息的话就跳过
            if (title_info_detail_list!=null){
                for (int i = 0; i < title_info_detail_list.size(); i++) {
                    Map<String, Object> map = title_info_detail_list.get(i);
                    String reg = map.get("reg").toString();
                    if (Pattern.matches(reg, join)){
                        return;
                    }
                }
            }

            for (int i = 0; i < s.size() ; i++) {
                Object content = s.get(i);
                ExceltitleDict exceltitleDict = exceltitleDictMap.get(i);
                if (exceltitleDict==null) continue;
                if (StringUtils.isBlank(s.get(i))) continue;
                //字段名称
                String classField = exceltitleDict.getClassField();
                //字段类型
                Class aClass = FieldTypeEnum.getFieldTypeEnumByVal(exceltitleDict.getFieldType());
                if (aClass.equals(Timestamp.class) ){
                    String time="";
                    String date="";
                    String dataTime="";
                    for (Map.Entry<Integer, ExceltitleDict> m : exceltitleDictMap.entrySet()) {
                        ExceltitleDict value = m.getValue();
                        if (value.getTitleValues().contains("交易时间")){
                            time= s.get(m.getKey())==null?"":s.get(m.getKey()).trim();
                            int timeLength = 6 - time.length();
                            if (time.length()<6){
                                for (int j = 0; j < timeLength; j++) {
                                    time+="0";
                                }
                            }
                        }
                        if (value.getTitleValues().contains("交易日期")){
                            date= s.get(m.getKey())==null?"":s.get(m.getKey()).trim();
                        }
                        dataTime=date+" "+time;
                        content=dataTime.trim();
                    }
                    Date d= DateUtils.getDate((String) content);
                    if (d==null) continue;
                    content = new Timestamp( d.getTime());
                }else if (aClass.equals(BigDecimal.class) ){
                    if (((String) content).contains(",")){
                        content = ((String) content).replaceAll(",","");
                    }
                    String s1=content.toString();
                    if (!Pattern.matches("([0-9]|\\.)+", s1)){
                        s1="0";
                    }
                    BigDecimal bigDecimal = new BigDecimal(s1);
                    //如果等于0就跳过，因为有的账单的交易金额是两个字段，比如说借方发生额，贷方发生额 肯定有一个是0
                    if (bigDecimal.compareTo(new BigDecimal("0"))==0){
                        continue;
                    }
                    if (Pattern.matches("([0-9]|\\.)+", s1)){
                        content=new BigDecimal((String) content);
                    }else {
                        continue;
                    }
                }else if (aClass.equals(Integer.class) ){
                    String s1 = content.toString();
                    if (Pattern.matches("[0-9]+", s1)){
                        content=Integer.valueOf(content.toString());
                    }else {
                        continue;
                    }
                }
                ReflectUtils.setValue(dealFlow,DealFlow.class,classField,aClass,content);
            }
            //判断dealFlow的字段内容是否都为null，如果是，就不添加
            if (checkObjFieldIsAllNull(dealFlow)) return;

            //设置存放头公共信息的map的值
            for (Map.Entry<String, String> m : title_attach_info_map.entrySet()) {
                //System.out.println("存放头公共信息的map的值->"+"key:" + m.getKey() + " value:" + m.getValue());
                String value = m.getValue();
                String[] split = value.split(",");
                if (ReflectUtils.isExistsFiled(DealFlow.class,m.getKey())){
                    Class aClass = FieldTypeEnum.getFieldTypeEnumByVal(Integer.valueOf(split[1]));
                    ReflectUtils.setValue(dealFlow,DealFlow.class,m.getKey(),aClass,split[0]);
                }
            }
            //设置存放循环公共信息的map的值
            for (Map.Entry<String, String> m : title_info_map.entrySet()) {
                System.out.println("存放循环公共信息的map的值->"+"key:" + m.getKey() + " value:" + m.getValue());
                String value = m.getValue();
                String[] split = value.split(",");
                if (ReflectUtils.isExistsFiled(DealFlow.class,m.getKey())){
                    Class aClass = FieldTypeEnum.getFieldTypeEnumByVal(Integer.valueOf(split[1]));
                    ReflectUtils.setValue(dealFlow,DealFlow.class,m.getKey(),aClass,split[0]);
                }

            }
            //对方卡号默认值
            if(StringUtils.isBlank(dealFlow.getAccountRivalCard())&&StringUtils.isNotBlank(dealFlow.getAccountRivalNumber())){
                dealFlow.setAccountRivalCard(dealFlow.getAccountRivalNumber());
            }
            //交易主体卡号默认值
            if(StringUtils.isBlank(dealFlow.getAccountBodyCard())&&StringUtils.isNotBlank(dealFlow.getAccountBodyNumber())){
                dealFlow.setAccountBodyCard(dealFlow.getAccountBodyNumber());
            }
            //收取标志
            if(excelRule.getIsInputOut()!=null){
                String isInputOut = excelRule.getIsInputOut();
                Map<String,String> string2Map = JsonUtil.string2Obj(isInputOut, Map.class);
                if (string2Map.get("type").equals("1")){
                    String col = s.get(Integer.valueOf(string2Map.get("col")));
                    if (string2Map.get("input").contains(col)){
                        dealFlow.setSign(0);
                    }else{
                        dealFlow.setSign(1);
                    }
                }else if (string2Map.get("type").equals("2")){
                    String col = string2Map.get("col");
                    String[] split = col.split(",");
                    String s1 = s.get(Integer.valueOf(split[0]));
                    s1=StringUtils.isBlank(s1)?"0":s1;
                    String s2 = s.get(Integer.valueOf(split[1]));
                    s2=StringUtils.isBlank(s2)?"0":s2;
                    if (s1.contains(",")){
                        s1 = s1.replaceAll(",","");
                    }
                    if (s2.contains(",")){
                        s2 = s2.replaceAll(",","");
                    }
                    BigDecimal bigDecimal = new BigDecimal(s1);
                    BigDecimal bigDecimal2 = new BigDecimal(s2);
                    if (bigDecimal.compareTo(bigDecimal2)==1){
                        dealFlow.setSign(0);
                    }else{
                        dealFlow.setSign(1);
                    }
                }else if (string2Map.get("type").equals("3")){
                    try {
                        String col = string2Map.get("col");
                        String[] split = col.split(",");
                        String filed1=split[0];
                        String filed2=split[1];
                        BigDecimal t= new BigDecimal(0);
                        if (this.dealFlow==null){ //如果交易金额比交易余额还大，那肯定是流出
                            BigDecimal v1 = ReflectUtils.getGetMethod(dealFlow, filed1)==null?t:(BigDecimal)ReflectUtils.getGetMethod(dealFlow, filed1);
                            BigDecimal v2 = ReflectUtils.getGetMethod(dealFlow, filed2)==null?t:(BigDecimal)ReflectUtils.getGetMethod(dealFlow, filed2);
                            if (v1!=null&&v2!=null&&v1.compareTo(v2)>0){
                                dealFlow.setSign(1);
                            }else{
                                dealFlow.setSign(0);
                            }
                        }else{
                            //旧交易余额
                            BigDecimal old_v2 =ReflectUtils.getGetMethod(this.dealFlow, filed2)==null?t:(BigDecimal)ReflectUtils.getGetMethod(this.dealFlow, filed2);
                            //新交易金额，交易余额
                            BigDecimal v1 = ReflectUtils.getGetMethod(dealFlow, filed1)==null?t:(BigDecimal)ReflectUtils.getGetMethod(dealFlow, filed1);
                            BigDecimal v2 = ReflectUtils.getGetMethod(dealFlow, filed2)==null?t:(BigDecimal)ReflectUtils.getGetMethod(dealFlow, filed2);
                            BigDecimal add = old_v2.add(v1);
                            if (add.compareTo(v2)==0){
                                dealFlow.setSign(0);
                            }else{
                                dealFlow.setSign(1);
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }else if (string2Map.get("type").equals("4")){
                    String val = string2Map.get("val");
                    if ("1".equals(val)){
                        dealFlow.setSign(1);
                    }else{
                        dealFlow.setSign(0);
                    }
                }else if (string2Map.get("type").equals("5")){
                    try {
                        Integer val1 = Integer.valueOf(string2Map.get("val1"));
                        Integer val2 = Integer.valueOf(string2Map.get("val2"));
                        String key = string2Map.get("key");
                        String fieldName = string2Map.get("fieldName");
                        if (title_info_map!=null&&title_info_map.containsKey(key)){
                            String s1 = title_info_map.get(key);
                            String fieldVal = ReflectUtils.getGetMethod(dealFlow, fieldName).toString();
                            if (s1.contains(fieldVal)){
                                dealFlow.setSign(val1);
                            }else{
                                dealFlow.setSign(val2);
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }else{
                dealFlow.setSign(0);
            }
            if (excelRule.getIsMultiTitleHead()!=null&&excelRule.getIsMultiTitleHead()==1){
                if (multiTitleHeadFlag!=1) {
                    this.dealFlow2=dealFlow;
                    return;
                }
            }
            this.dealFlow=dealFlow;
            if(excelRule.getIsSpecial()!=null&&excelRule.getIsSpecial()==1){
                String specialDetail = excelRule.getSpecialDetail();
                Map<String,Object> string2Map = JsonUtil.string2Obj(specialDetail, Map.class);
                String field = string2Map.get("field").toString();
                String equal = string2Map.get("equal").toString();
                try {
                    String fieldVal = ReflectUtils.getGetMethod(dealFlow, field).toString();
                    if (fieldVal.equals(equal)){
                        String accountBody = dealFlow.getAccountBody();
                        String accountBodyCard = dealFlow.getAccountBodyCard();
                        String accountBodyNumber = dealFlow.getAccountBodyNumber();
                        String accountBodyBank = dealFlow.getAccountBodyBank();

                        String accountRivalCard = dealFlow.getAccountRivalCard();
                        String accountRival = dealFlow.getAccountRival();
                        String accountRivalNumber = dealFlow.getAccountRivalNumber();
                        String accountRivalBank = dealFlow.getAccountRivalBank();

                        dealFlow.setAccountRival(accountBody);
                        dealFlow.setAccountRivalCard(accountBodyCard);
                        dealFlow.setAccountRivalNumber(accountBodyNumber);
                        dealFlow.setAccountRivalBank(accountBodyBank);
                        dealFlow.setAccountBody(accountRival);
                        dealFlow.setAccountBodyCard(accountRivalCard);
                        dealFlow.setAccountBodyNumber(accountRivalNumber);
                        dealFlow.setAccountBodyBank(accountRivalBank);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            data.add(dealFlow);
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        /*for (int i = 0; i < data.size(); i++) {
            System.out.println(data.get(i));
        }
        System.out.println("一共："+data.size());*/
        Integer size=0;
        if (resultMap.containsKey("successNum")){
            size = (Integer) resultMap.get("successNum");
            size+=data.size();
        }else{
            size=data.size();
        }
        resultMap.put("successNum",size);
        data = new ArrayList<DealFlow>();
    }

    /**
     * 检查对象的字段是否全部为null
     * @param obj
     * @return
     */
    public  boolean checkObjFieldIsAllNull(Object obj)  {
        boolean flag = false;
        int count=0;
        try {
            for (int i = 0; i < obj.getClass().getDeclaredFields().length; i++) {
                Field f = obj.getClass().getDeclaredFields()[i];
                f.setAccessible(true);
                if(f.get(obj) == null){
                    count++;
                }
            }
            if (count==obj.getClass().getDeclaredFields().length){
                flag=true;
            }
        }catch (Exception e){
            return true;
        }finally {
            return flag;
        }
    }

    public List<DealFlow> getList() {
        return list;
    }

    public void setList(List<DealFlow> list) {
        this.list = list;
    }

    public Map<String, Object> getParaMap() {
        return paraMap;
    }

    public void setParaMap(Map<String, Object> paraMap) {
        this.paraMap = paraMap;
    }

    public Map<String, Object> getResultMap() {
        return resultMap;
    }

    public void setResultMap(Map<String, Object> resultMap) {
        this.resultMap = resultMap;
    }

    public ExcelRule getExcelRule() {
        return excelRule;
    }

    public void setExcelRule(ExcelRule excelRule) {
        this.excelRule = excelRule;
    }

    public Map<Integer, ExceltitleDict> getExceltitleDictMap() {
        return exceltitleDictMap;
    }

    public void setExceltitleDictMap(Map<Integer, ExceltitleDict> exceltitleDictMap) {
        this.exceltitleDictMap = exceltitleDictMap;
    }

    public Map<Integer, ExceltitleDict> getExceltitleDictMapBak() {
        return exceltitleDictMapBak;
    }

    public void setExceltitleDictMapBak(Map<Integer, ExceltitleDict> exceltitleDictMapBak) {
        this.exceltitleDictMapBak = exceltitleDictMapBak;
    }
}
